

#include "URL.h"
#include <iostream>
#include <list>
#include <map>
#include "URLFileDealer.h"
#include <boost/tr1/memory.hpp>
#include <boost/thread/mutex.hpp>

#include "../classes_dados/Hasher.h"
#include "../classes_dados/URLDiskClass.h"


using namespace std;
using namespace __gnu_cxx;

std::tr1::shared_ptr<URLFileDealer> URLFileDealer::theURLFileDealer(new URLFileDealer);

//URLFileDealer * URLFileDealer::getInstance()
//{
//	//Cuidado no multithreading...
//    if(theURLFileDealer == NULL)
//    	theURLFileDealer = new URLFileDealer();
//    return theURLFileDealer;
//}



void URLFileDealer::addToDiskBuffer(URL * url){ 
	boost::mutex::scoped_lock diskBufferLock(diskBufferMutex);
	//URL * urlPointer = new URL(url);
   	//toDiskBuffer.push_back(url);
//   	if ((toDiskBuffer.size()%1000) == 3)
//   		std::cout << "MC suga pelo menos " << toDiskBuffer.size() << " pessoas por dia" << std::endl; 
   	
   //	cout << "Aqui em URLFileDealer::addToDiskBuffer, url: " << url->toString() << endl;
   	discoUrl.writeDisk(*url);
   	//cout << "Tamanho do disco: " << discoUrl.size() << endl;
   	
   	delete url;
   	
   	return;
}



list<URL *> URLFileDealer::getNewURLs() {
	boost::mutex::scoped_lock diskBufferLock(diskBufferMutex);
	string urlHash;
	string urlString;
	list<URL>::iterator it;
	
	list<URL *> tempList;// = toDiskBuffer;
	URL * tempUrl;
	
	long long tamanho = discoUrl.totalNewURLs();
	
//	cout << "Tamanho do Disco: " << tamanho << endl;
	
	
//	cout << "Aqui !!! : 01 " << endl;
	
	if(tamanho > 0){
		if(tamanho > maxNumUrlsFromDisk) tamanho = maxNumUrlsFromDisk;  // limita tamanho		
		for (long long i = 0; i<tamanho; i++) {
			tempUrl = new URL( discoUrl.readDisk() );
			//cout << "gente, olha a url q o MC retornou: " << tempUrl->toString() << endl;
			tempList.push_back(tempUrl);
			
//			cout << "Aqui !!! : 02 " << endl;
		}
	}else{
		// se aqui, dico vazio....
		// pega lista esperando para ser gravada e grava, e executa a leitura
		
//		cout << "Aqui !!! : 03 " << endl;
		
		for (it = listURLtoWrite.begin(); it!=listURLtoWrite.end(); it++){
					urlString = it->toString();
					urlHash = Hasher::md5(urlString);
					if  (urlHashMap[urlHash] == false){ //verifica se tem 
						urlHashMap[urlHash] = true;     //marca que agora tem
						addToDiskBuffer(new URL(*it));  //grava
					}		
				}
				listURLtoWrite.clear(); //limpa lista que foi gravada		
				tamanho = discoUrl.totalNewURLs();
				if(tamanho > 0){
					if(tamanho > maxNumUrlsFromDisk) tamanho = maxNumUrlsFromDisk;
					for (long long i = 0; i<tamanho; i++){
						tempUrl = new URL( discoUrl.readDisk() );
						tempList.push_back(tempUrl);
					}
				}
	}
	return tempList;
}



void URLFileDealer::initURLHashMap(URL _addUrl){
	string urlHash = "";
	
	boost::mutex::scoped_lock urlHashMapLock(urlHashMapMutex);
	
	urlHash = Hasher::md5(_addUrl.toString());
	if  (urlHashMap[urlHash] == false) 	urlHashMap[urlHash] = true;	
}


void URLFileDealer::addURLs(std::list<URL> urlList) {
	string urlString = "";
	string urlHash = "";
	list<URL>::const_iterator it;
//	int i = 0;
	boost::mutex::scoped_lock urlHashMapLock(urlHashMapMutex);
	
	// adiciona lista de entrada na lista de URL para escrita;
	for (it = urlList.begin(); it!=urlList.end(); it++)listURLtoWrite.push_back(*it);
	// se a lista de escrita atinge tamanho maximo, grava no disco
	
	if(listURLtoWrite.size() > 1000){
		for (it = listURLtoWrite.begin(); it!=listURLtoWrite.end(); it++){
			urlString = it->toString();
			urlHash = Hasher::md5(urlString);
//			if  (urlHashMap[urlHash].get_dominio() == ""){
//	//			cout << "TOIN: " << it->get_dominio() << endl;
//	//			cout << "TOIN2: " << it->get_path() << endl;
//				urlHashMap[urlHash] = *it;
//				addToDiskBuffer(new URL(*it));
//			}
			//trata urlHashMap[urlHash] de modo diferente, para poupar mem...
			if  (urlHashMap[urlHash] == false){ //verifica se tem 
				urlHashMap[urlHash] = true;     //marca que agora tem
				addToDiskBuffer(new URL(*it));  //grava
				
//				cout << "Gravando no disco... " << endl;
				
			}		
		}
		listURLtoWrite.clear(); //limpa lista que foi gravada
	}
}



